package com.s.remotelog.wifi;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.NetworkInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.SystemClock;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.util.Log;

import java.util.List;

public class WifiOpImpl implements IWifiOperator {

    private static final String TAG = "RLog";

    private static final String DEFAULT_AP_HOST_IP = "192.168.43.1";

    private Context mContext;
    private WifiManager mWifiManager;
    private ConnectivityManager mConnMgr;
    private boolean mConnecting;

    public WifiOpImpl(Context context) {
        mContext = context;
        mWifiManager = (WifiManager) context.
                getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        mConnMgr = (ConnectivityManager) context.
                getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
    }

    @Override
    public boolean enableWifi() {
        if (mWifiManager.isWifiEnabled()) {
            return true;
        }
        return mWifiManager.setWifiEnabled(true);
    }

    @Override
    public boolean disableWifi() {
        return mWifiManager.setWifiEnabled(false);
    }

    @Override
    public boolean connWifiSync(String ssid, String pwd, String type, int tryTimes) {
        Log.i(TAG, "connect wifi with : " + ssid + " " + pwd + " " + type);
        return connHost(ssid, pwd, type, tryTimes);
    }

    @Override
    public void connWifiAsync(final String ssid, final String pwd, final String type, final int tryTimes, final IWifiConnCallback callback) {
        Runnable connTask = new Runnable() {
            @Override
            public void run() {
                boolean conn = connHost(ssid, pwd, type, tryTimes);
                if (callback != null) {
                    callback.onConnCallback(conn);
                }
            }
        };
        new Thread(connTask,"conn-wifi").start();
    }


    private boolean connHost(String ssid, String pwd, String type, int maxTryTimes) {
        Log.i(TAG, "in connHost first");
        synchronized (this) {
            if (mConnecting) {
                Log.i(TAG, "wifi is connecting, wait !");
                return false;
            }
        }

        try {
            synchronized (this) {
                mConnecting = true;
            }

            // is already connected, to compare the ssid
            // if the connected wifi same as requesting,
            // we think success
            Log.i(TAG, "to check wifi is connected ... ");
            if (isWifiConn()) {
                Log.i(TAG, "wifi is connected, will check ssid");
                String connSSID = getWifiSSID();
                if (TextUtils.equals(ssid, connSSID)) {
                    Log.i(TAG, "already conn ssid :" + connSSID);
                    return true;
                }
            }

            // try to connect one time, if connected, success
            boolean firstTry = connHost(ssid, pwd, type, maxTryTimes);
            Log.i(TAG, "try first time, connect : " + firstTry);
            if (firstTry) {
                return true;
            }

            int times = 0;
            while (times++ < maxTryTimes) {
                Log.i(TAG, "will start scan ...");
                mWifiManager.startScan();
                SystemClock.sleep(3000);
                List<ScanResult> results = mWifiManager.getScanResults();

                Log.i(TAG, "try times : " + times + " scan size : "
                        + (results != null ? results.size() : 0));

                if (results == null || results.isEmpty()) {
                    // if try 10 times, still no result,
                    // we re-open wifi and re-try
                    if (times % 10 == 0) {
                        mWifiManager.setWifiEnabled(false);
                        SystemClock.sleep(3000);
                        mWifiManager.setWifiEnabled(true);
                    }
                    continue;
                }


                boolean findHost = false;
                for (ScanResult result : results) {
                    if (TextUtils.equals(result.SSID, ssid)) {
                        findHost = true;
                        break;
                    }
                }

                if (findHost) {
                    boolean conn = connectWifi(ssid, pwd, type);
                    Log.i(TAG, "conn to host : " + conn);
                    if (conn) {
                        return true;
                    }
                } else {
                    Log.e(TAG, "Not find our AP !");
                }
            }
        } finally {
            synchronized (this) {
                mConnecting = false;
            }
        }
        return false;
    }

    private boolean connectWifi(String targetSsid, String targetPsd, String enc) {
        String ssid = "\"" + targetSsid + "\"";
        String psd = "\"" + targetPsd + "\"";

        WifiConfiguration conf = new WifiConfiguration();
        conf.SSID = ssid;
        switch (enc) {
            case "WEP":
                conf.wepKeys[0] = psd;
                conf.wepTxKeyIndex = 0;
                conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
                conf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
                break;
            case "WPA":
                conf.preSharedKey = psd;
                break;
            case "OPEN":
                conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
        }

        mWifiManager.addNetwork(conf);
        List<WifiConfiguration> list = mWifiManager.getConfiguredNetworks();
        for (WifiConfiguration i : list) {
            if (i.SSID != null && i.SSID.equals(ssid)) {
                boolean disConn = mWifiManager.disconnect();
                boolean add = mWifiManager.enableNetwork(i.networkId, true);
                boolean conn = mWifiManager.reconnect();
                return disConn && add && conn;
            }
        }
        return false;
    }

    public String getApHostIp() {
        DhcpInfo info = mWifiManager.getDhcpInfo();
        String ip = Formatter.formatIpAddress(info.serverAddress);
        if (TextUtils.isEmpty(ip)) {
            return "";
        }

        if (!ip.startsWith("192.168")) {
            return DEFAULT_AP_HOST_IP;
        }
        return ip;
    }

    private String getWifiSSID() {
        WifiInfo info = mWifiManager.getConnectionInfo();
        if (info == null) {
            return null;
        }
        return info.getSSID();
    }

    //
    //
    public boolean isWifiConn() {
        NetworkInfo info = mConnMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        //Log.i(TAG, "the wifi info is : " + info.toString());
        return info.isConnected();
    }

    public boolean isConn() {
        NetworkInfo info = mConnMgr.getActiveNetworkInfo();
        if (null != info && info.isConnected()) {
            return info.getState() == NetworkInfo.State.CONNECTED;
        }
        return false;
    }
}
